package com.hqbzl.c1.rlock;

import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.IntStream;

//4个线程依次打印ABCD,循环指定次数
@Slf4j
public class SequenceWrite {

    public static void main(String[] args) {
        final Writer writer = new Writer(100, 4);
        new Thread(() -> {
            writer.print("a", 0);
        }, "thread-a").start();
        new Thread(() -> {
            writer.print("b", 1);
        }, "thread-b").start();
        new Thread(() -> {
            writer.print("c", 2);
        }, "thread-c").start();
        new Thread(() -> {
            writer.print("d", 3);
        }, "thread-d").start();

    }

    static class Writer {
        ReentrantLock room = new ReentrantLock();
        final List<Condition> conditions = new ArrayList<>();

        private void print(String str, int index) {
            room.lock();
            try {
                for (int i = 0; i < num; i++) {
                    // 如果不是当前的，就阻塞
                    while (index != currentIndex) {
                        try {
                            conditions.get(index).await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.print(str);
                    currentIndex++;
                    if (currentIndex >= conditions.size()) {
                        currentIndex = 0;
                    }
                    conditions.get(currentIndex).signal();
                }
            } finally {
                room.unlock();
            }
        }

        // 当前索引
        private int currentIndex = 0;
        // 循环次数
        private int num;

        public Writer(int num, int execThreadSize) {
            for (int i = 0; i < execThreadSize; i++) {
                conditions.add(room.newCondition());
            }
            this.num = num;
        }
    }

}
